#include "login_connect_task.h"

#include <core/QbLogger.h>
#include <core/system/thread_wrapper.h>
#include <qbkernel/include/qb_base.h>

#ifndef _MSC_VER
#include <arpa/inet.h>
#endif

namespace qb {
CLoginConnectTask::CLoginConnectTask() : m_pThread(NULL), m_uThreadId(0) {}

CLoginConnectTask::~CLoginConnectTask() {
  if (IsRunning()) {
    Cleanup();
  }
}

void CLoginConnectTask::StartImpl() { StartConnecting(); }

void CLoginConnectTask::TerminateImpl() { Cleanup(); }

void CLoginConnectTask::OnNetStatus(int32_t status) { OnConnect(status); }

void CLoginConnectTask::OnTimeout() {
  log_debug("connect LoginServer timeout");
  StopThread();
  NotifyFailed(loginData::instance().GetCurrentStatus(),
               eNetError_ConnectServerTimeout);
}

bool CLoginConnectTask::ThreadCallback(void* args) {
  CLoginConnectTask* pConnectTask = (CLoginConnectTask*)args;
  QB_CHECK_RETURN_BOOL_ASSERT1(pConnectTask);

  return pConnectTask->ThreadProcess();
}

bool CLoginConnectTask::ThreadProcess() {
  if (eNetStatus_ConnectingLogin == loginData::instance().GetCurrentStatus()) {
    if (!Connect(loginData::instance().GetServerLoginAddress())) {
      log_error("%s can't connect LoginServer", __FUNCTION__);
    }
  } else if (eNetStatus_ConnectingGW ==
             loginData::instance().GetCurrentStatus()) {
    if (!Connect(loginData::instance().GetGatewayLoginAddress())) {
      log_error("%s can't connect LoginServer", __FUNCTION__);
    }
  }

  return false;
}

void CLoginConnectTask::StartConnecting() {
  if (eNetStatus_None == loginData::instance().GetCurrentStatus()) {
    // 更新当前步骤
    loginData::instance().SetCurrentStatus(eNetStatus_ConnectingLogin);

    // 通知observers当前的登录步骤
    NotifyLoginStep(eNetStatus_ConnectingLogin, 0);
  } else if (eNetStatus_VerifyLogin ==
             loginData::instance().GetCurrentStatus()) {
    // 更新当前步骤
    loginData::instance().SetCurrentStatus(eNetStatus_ConnectingGW);

    // 通知observers当前的登录步骤
    NotifyLoginStep(eNetStatus_ConnectingGW, 0);
  }

  // 开始连接线程
  if (!StartThread()) {
    NotifyFailed(loginData::instance().GetCurrentStatus(),
                 (short)eNetErrorCode::eNetError_ConnectServerError);
    return;
  }

  log_debug("connect verify server step [%s:%u]",
            loginData::instance().GetServerLoginAddress().strIPAdress.c_str(),
            loginData::instance().GetServerLoginAddress().uPort);
}

bool CLoginConnectTask::StartThread() {
  if (m_pThread) {
    log_error("%s stop the exist thread");
    StopThread();
  }

  m_pThread = ThreadWrapper::CreateThread(ThreadCallback, this, kNormalPriority,
                                          "LoginBaseTaskThreadCallback");
  if (!m_pThread) {
    log_error("thread not created");
    return false;
  }

  if (!m_pThread->Start(m_uThreadId)) {
    log_error("thread not start");

    // delete the thread object
    ThreadWrapper* pThread = m_pThread;
    m_pThread = NULL;
    delete pThread;

    NotifyFailed(loginData::instance().GetCurrentStatus(),
                 (short)eNetErrorCode::eNetError_CreateThreadFailed);

    return false;
  }

  return true;
}

void CLoginConnectTask::StopThread() {
  ThreadWrapper* tmpPtr = m_pThread;
  QB_CHECK_RETURN_VOID1(tmpPtr);

  m_pThread = NULL;
  tmpPtr->SetNotAlive();

  int32_t nTryCount = 6;
  while (--nTryCount >= 0) {
    if (tmpPtr->Stop()) {
      delete tmpPtr;
      break;
    }
  }

  // error
  if (nTryCount < 0) {
    bool bForce = false;
    tmpPtr->Stop(bForce);
    if (bForce) {
      delete tmpPtr;
    }

    log_warning("stop thread failed, and we force terminate it");
  }
}

bool CLoginConnectTask::Connect(const tIPAdressPort& ipAddressPort) {
  return qbBase::getMessageKernel()->Connect(loginData::instance().ConnectID(),
                                             ipAddressPort.strIPAdress.c_str(),
                                             ipAddressPort.uPort) == 0
             ? true
             : false;
}

void CLoginConnectTask::OnConnect(int32_t status) {
  // print log
  switch (status) {
    case kConnectTimeout:
      log_debug("connect timeout");
      break;
    case kConnectError:
      log_debug("network error");
      break;
    case kConnectConnectFailed:
      log_debug("connect failed");
      break;
    default:
      break;
  }

  // 停止时钟
  StopTaskTimer();

  // 停止连接线程
  StopThread();

  if (kConnectConnected == status) {
    if (eNetStatus_ConnectingLogin ==
        loginData::instance().GetCurrentStatus()) {
      // 更新当前步骤
      loginData::instance().SetCurrentStatus(eNetStatus_ConnectedLogin);

      // 通知observers当前的登录步骤
      NotifyLoginStep(eNetStatus_ConnectedLogin, 0);
    } else if (eNetStatus_ConnectingGW ==
               loginData::instance().GetCurrentStatus()) {
      // 更新当前步骤
      loginData::instance().SetCurrentStatus(eNetStatus_ConnectedGW);

      // 通知observers当前的登录步骤
      NotifyLoginStep(eNetStatus_ConnectedGW, 0);
    }

    NotifyFinished();
  } else {
    NotifyFailed(loginData::instance().GetCurrentStatus(),
                 (short)eNetErrorCode::eNetError_ConnectServerError);
  }
}

void CLoginConnectTask::Disconnect() {
  qbBase::getMessageKernel()->CloseConnect(loginData::instance().ConnectID());
}

void CLoginConnectTask::Cleanup() {
  //    Disconnect();
  StopTaskTimer();
  StopThread();
}
}  // namespace qb
